#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"
#include "esp_tls.h"
#include "math.h"

#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_task_wdt.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"

#include "cJSON.h"
#include "esp_task_wdt.h"
#include "driver/uart.h"
#include "pan_main.h"
#include "mqtt_client.h"

#define FIRMWARE_PACKAGE_LENGTH 512
static const char *TAG = "PAN_HTTP";
FIRMWARE_INFO FirmwareInfo;

static int firmwareoffset = 0;
static int firmwarelength = 0;
static uint8_t ota_progress = 0;
static char *ptr;

extern esp_mqtt_client_handle_t user_client;
extern uint8_t MqttConnectFlag;
extern uint8_t OTAflag;
extern char ota_progress_topic[80];
extern xQueueHandle start_OTA_queue;
extern APP_INFO app_info;
extern APP_INFO ver_info;
extern int esp_https_ota_get_image_total_len(esp_https_ota_handle_t https_ota_handle);

uint32_t OPENBL_CRC32_MPEG_2(char *data, uint32_t length)
{
    uint32_t i;
    uint32_t crc = 0xffffffff, j = 0;

    while ((length--) != 0)
    {
        crc ^= (uint32_t)data[j] << 24;
        j++;
        for (i = 0; i < 8; ++i)
        {
            if ((crc & 0x80000000) != 0)
            {
                crc = (crc << 1) ^ 0x04C11DB7;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return crc;
}

static void send_ota_done(void) // 数据的长度（不是一帧的长度）
{
    char len = 1;
    char buff[len + 13];
    uint32_t crc;
    int i;

    buff[0] = 0xA5;
    buff[1] = 0x5A;
    buff[2] = (uint8_t)(len + 9);
    buff[3] = (uint8_t)((len + 9) >> 8);
    buff[4] = 0x13; // 控制字
    buff[5] = (uint8_t)(FirmwareInfo.BinCurrentNo);
    buff[6] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 8);
    buff[7] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 16);
    buff[8] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 24);
    for (i = 0; i < len; i++)
        buff[9 + i] = 0xFF;

    crc = OPENBL_CRC32_MPEG_2(buff, len + 9);
    buff[9 + len] = (uint8_t)crc;
    buff[9 + len + 1] = (uint8_t)(crc >> 8);
    buff[9 + len + 2] = (uint8_t)(crc >> 16);
    buff[9 + len + 3] = (uint8_t)(crc >> 24);

    for (i = 0; i < 5; i++)
    {
        sendData(buff, len + 13);
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

static void send_ota_bin(char *data, int len) // 数据的长度（不是一帧的长度）
{
    char buff[len + 13];
    uint32_t crc;
    int i;

    buff[0] = 0xA5;
    buff[1] = 0x5A;
    buff[2] = (uint8_t)(len + 9);
    buff[3] = (uint8_t)((len + 9) >> 8);
    buff[4] = 0x12; // 控制字
    buff[5] = (uint8_t)(FirmwareInfo.BinCurrentNo);
    buff[6] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 8);
    buff[7] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 16);
    buff[8] = (uint8_t)(FirmwareInfo.BinCurrentNo >> 24);
    for (i = 0; i < len; i++)
        buff[9 + i] = data[i];

    crc = OPENBL_CRC32_MPEG_2(buff, len + 9);
    buff[9 + len] = (uint8_t)crc;
    buff[9 + len + 1] = (uint8_t)(crc >> 8);
    buff[9 + len + 2] = (uint8_t)(crc >> 16);
    buff[9 + len + 3] = (uint8_t)(crc >> 24);

    for (i = 0; i < 15; i++)
    {
        OTAflag = 0; // 等待单片机回复
        sendData(buff, len + 13);
        ESP_LOGI(TAG, " BinCurrentByte: %d", FirmwareInfo.BinCurrentNo);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        if (1 == OTAflag)
        {
            FirmwareInfo.BinCurrentNo += len;
            ESP_LOGI(TAG, "OTAflag=1,OTAInfo BinCurrentByte: %d", FirmwareInfo.BinCurrentNo);
            return;
        }
        else if (2 == OTAflag)
        {
            ESP_LOGI(TAG, "OTAflag=2,OTAInfo resend: %d", i);
        }
        else if (3 == OTAflag)
        {
            ESP_LOGI(TAG, "OTAflag=3,OTAInfo resend: %d", i);
            FirmwareInfo.BinCurrentNo += len;
            ESP_LOGI(TAG, "OTA bin sent over BinCurrentByte: %d", FirmwareInfo.BinCurrentNo);
            return;
        }
        else
            ESP_LOGI(TAG, "OTAflag=0,OTAInfo resend: %d", i);
    }
}

static void send_ota_Info()
{
    char buff[17], i;
    uint32_t crc;

    buff[0] = 0xA5;
    buff[1] = 0x5A;
    buff[2] = 0x0D;
    buff[3] = 0x00;
    buff[4] = 0x11; // 控制字
    buff[5] = FirmwareInfo.version[0];
    buff[6] = FirmwareInfo.version[1];
    buff[7] = FirmwareInfo.version[2];
    buff[8] = FirmwareInfo.version[3];
    buff[9] = (uint8_t)firmwarelength;
    buff[10] = (uint8_t)(firmwarelength >> 8);
    buff[11] = (uint8_t)(firmwarelength >> 16);
    buff[12] = (uint8_t)(firmwarelength >> 24);
    crc = OPENBL_CRC32_MPEG_2(buff, 13);
    buff[13] = (uint8_t)crc;
    buff[14] = (uint8_t)(crc >> 8);
    buff[15] = (uint8_t)(crc >> 16);
    buff[16] = (uint8_t)(crc >> 24);

    for (i = 0; i < 5; i++)
    {
        OTAflag = 0; // 等待单片机回复
        sendData(buff, 17);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        if (1 == OTAflag)
        {
            ESP_LOGI(TAG, "OTAflag=1,OTAInfo resend: %d", i);
            return;
        }
        else if (2 == OTAflag)
        {
            ESP_LOGI(TAG, "OTAflag=2,OTAInfo resend: %d", i);
        }
        else
            ESP_LOGI(TAG, "OTAflag=0,OTAInfo resend: %d", i);
    }
}
static void send_GoIntoOTA()
{
    char buff[9], i;
    uint32_t crc;

    buff[0] = 0xA5;
    buff[1] = 0x5A;
    buff[2] = 0x05;
    buff[3] = 0x00;
    buff[4] = 0x10; // 控制字

    crc = OPENBL_CRC32_MPEG_2(buff, 5);
    buff[5] = (uint8_t)crc;
    buff[6] = (uint8_t)(crc >> 8);
    buff[7] = (uint8_t)(crc >> 16);
    buff[8] = (uint8_t)(crc >> 24);

    for (i = 0; i < 15; i++)
    {
        OTAflag = 0; // 等待单片机回复
        sendData(buff, 9);

        vTaskDelay(1000 / portTICK_PERIOD_MS);
        if (1 == OTAflag)
        {
            ESP_LOGI(TAG, "GO INTO OTA resend: %d", i);
            return;
        }
        else if (2 == OTAflag)
        {
            ESP_LOGI(TAG, "GO INTO OTA OTAflag=2,OTAInfo resend: %d", i);
        }
        else
            ESP_LOGI(TAG, "GO INTO OTA OTAflag=0,OTAInfo resend: %d", i);
    }
}
static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
{
    if (new_app_info == NULL)
    {
        return ESP_ERR_INVALID_ARG;
    }

    const esp_partition_t *running = esp_ota_get_running_partition(); //	获取当前系统执行的固件所在的Flash分区
    esp_app_desc_t running_app_info;
    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK)
    {
        ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
        ESP_LOGI(TAG, "New firmware version: %s", new_app_info->version);
    }

    if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0)
    {
        ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
        // pan        return ESP_FAIL;
    }
    return ESP_OK;
}

char recv_bin_last_package[512] = {0};
char recv_bin_last_package_length = 0;
TickType_t LastPackage_OverCount = 0;
static void __ota_for_self(char *rxmsg)
{
    ESP_LOGI(TAG, "Starting wifi OTA example");
    char last_package_flag = 0;
    char str[512] = {0};
    char Progress_str[32] = {0};
    cJSON *cjson_OTA = NULL;
    HttpInfo_t *httpinfo;
    esp_err_t ota_finish_err = ESP_OK;
    uint16_t ErrorID = SYS_OK;
    LastPackage_OverCount = xTaskGetTickCount();
    for (uint8_t try = 0; try < 5; try++)
    {
        firmwarelength = 0;
        ota_progress = 0;
        ErrorID = SYS_OK;
        httpinfo = malloc(sizeof(HttpInfo_t));
        if (httpinfo == NULL)
        {
            ESP_LOGI(TAG, "Error,no enought space to malloc for httpinfo,which need %d bytes", sizeof(HttpInfo_t));
            ErrorID = SYS_ERR_NO_MEMORY;
            break;
        }
        httpinfo->URL = rxmsg;
        sscanf(httpinfo->URL + 8, "%[^/]", httpinfo->Server);
        sprintf(httpinfo->Request, "GET "
                                   "%s"
                                   " HTTP/1.1\r\n",
                httpinfo->URL);

        ESP_LOGI(TAG, "starting OTA progress,it has tried %d times...\r\n"
                      "http request is:\r\n"
                      "%s",
                 try, httpinfo->Request);

        esp_http_client_config_t config = {
            .url = httpinfo->URL,
            .timeout_ms = 5000,
            //.cert_pem = (char *)server_cert_pem_start,
            .skip_cert_common_name_check = true,
        };

        esp_https_ota_config_t ota_config = {
            .http_config = &config,
        };

        esp_https_ota_handle_t https_ota_handle = NULL;
        esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
        //    if (https_ota_handle == NULL) {
        // return ESP_FAIL;
        // }
        if (err != ESP_OK)
        {
            ESP_LOGI(TAG, "Error,esp_https_ota_begin failed");
            ErrorID = SYS_ERR_HTTPS_OTA_BEGIN_FAILED;
            goto ota_end;
        }

        esp_app_desc_t app_desc;
        /* 从图像标题读取应用程序描述。应用程序描述提供图像的 固件版本等信息 */
        err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
        if (err != ESP_OK)
        {
            ESP_LOGI(TAG, "Error,esp_https_ota_read_img_desc failed");
            ErrorID = SYS_ERR_HTTPS_OTA_READ_IMG_DESC_FAILED;
            goto ota_end;
        }

        err = validate_image_header(&app_desc);
        if (err != ESP_OK)
        {
            ESP_LOGI(TAG, "Error,image header verification failed");
            ErrorID = SYS_ERR_IMAGE_HEADER_VERIFICATION_FAILED;
            goto ota_end;
        }

        firmwarelength = esp_https_ota_get_image_total_len(https_ota_handle);
        ESP_LOGI(TAG, "firmware length=%d", firmwarelength);

        while (1)
        {
            ESP_LOGD(TAG, "ESP32 Update OverTime is %d  Tick %d", LastPackage_OverCount, xTaskGetTickCount());
            err = esp_https_ota_perform(https_ota_handle);
            if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS)
            {
                break;
            }

            /*输出OTA进度 ： 目前为止所读取的OTA图像数据*/
            if (((float)esp_https_ota_get_image_len_read(https_ota_handle)) >= (((float)firmwarelength) / 100) * ota_progress)
            {
                ota_progress++;
                if (ota_progress >= 100)
                {
                    ota_progress = 100;
                    ESP_LOGI(TAG, "!!!!! ESP32 OTA Done !!!!!");
                    ESP_ERROR_CHECK(user_nvs_save_blob(NVS_VER_INFO, &app_info, sizeof(app_info)));
                    // user_nvs_read_blob(NVS_VER_INFO, &ver_info, sizeof(ver_info));
                    // ESP_LOGI(TAG, "version: %d:%d:%d", ver_info.version[0], ver_info.version[1], ver_info.version[2]);
                }
                else
                {
                    // xQueueSend(OTAprogress_queue,&ota_progress,pdMS_TO_TICKS(0));
                }
                // NOTE: ESP32上传升级的进度
                cjson_OTA = cJSON_CreateObject();
                ESP_LOGI(TAG, "firmware upgrade progress = %d%%", ota_progress);
                sprintf(Progress_str, "%d%%", ota_progress);
                ESP_LOGI(TAG, "Update OTA Progress!!");
                /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
                cJSON_AddStringToObject(cjson_OTA, "Type", "ESP");
                /* 添加一条浮点类型的JSON数据(添加一个链表节点) */
                cJSON_AddStringToObject(cjson_OTA, "Progress", Progress_str);
                /* 打印JSON对象(整条链表)的所有数据 */
                memcpy(str, cJSON_Print(cjson_OTA), 512);
                ESP_LOGI(TAG, "%s", str);
                esp_mqtt_client_publish(user_client, (const char *)&ota_progress_topic, (const char *)str, strlen(str), 0, 0);
                // 清除
                cJSON_Delete(cjson_OTA);
                // 超时3min或者到进度条
                if (xTaskGetTickCount() - LastPackage_OverCount >= ((100) * (60) * (3)) || ota_progress == 100)
                {
                    ESP_LOGE(TAG, "!!!!! ESP32 Update Over Ready to Reboot !!!!!");
                    if (recv_bin_last_package_length > 0)
                    {
                        last_package_flag = 1;
                    }
                    else
                    {
                        ESP_LOGW(TAG, "None GD32 Image");
                    }
                }
            }
        }
        if (esp_https_ota_is_complete_data_received(https_ota_handle) != true)
        {
            // the OTA image was not completely received and user can customise the response to this situation.
            ESP_LOGI(TAG, "Error,Complete data was not received.");
            ErrorID = SYS_ERR_COMPLETE_DAT_WAS_NOT_RECEIVED;
        }
        else
        {
            ota_progress = 100;
            // xQueueSend(OTAprogress_queue,&ota_progress,pdMS_TO_TICKS(5000));
        }
    ota_end:
        ota_finish_err = esp_https_ota_finish(https_ota_handle);
        free(httpinfo);
        SendToServerOTAover(); // MQTT通知升级结束
        if ((err == ESP_OK) && (ota_finish_err == ESP_OK))
        {
            ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade success. system will reboot in 5 sections ..."); 
            send_ota_done();
            for (uint8_t i = 5; i > 0; i--)
            {
                vTaskDelay(1000 / portTICK_PERIOD_MS);
                ESP_LOGI(TAG, "%d", i);
            }
            ESP_LOGI(TAG, "Rebooting ...");
            esp_restart();
        }
        else
        {
            if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED)
            {
                ESP_LOGI(TAG, "Error,Image validation failed, image is corrupted");
                ErrorID = SYS_ERR_IMAGE_VALIDATION_FAILED;
            }
            ESP_LOGI(TAG, "ErrorESP_HTTPS_OTA upgrade failed %d", ota_finish_err);
        }
    }
}

#define WEB_SERVER "dev.dewokang.com"
#define WEB_PORT "12000"
#define WEB_PATH "/10005/mods/mattress/1.1.1"
char recv_buf_temp[1024] = {0};
char my_recv_buf_temp[1024] = {0};
char recv_bin_file_temp[512] = {0};
int MyStrstr(char *str, char *substr)
{
    int num = 0;
    while (*str != '\0')
    {
        if (*str != *substr)
        {
            str++;
            num++;
            continue;
        }

        // 创建临时指针
        char *tmpstr = str;
        char *tmpsubstr = substr;

        while (*tmpsubstr != '\0')
        {
            if (*tmpstr != *tmpsubstr)
            {
                // 匹配失败
                str++;
                num++;
                break;
            }
            tmpstr++;
            tmpsubstr++;
        }
        if (*tmpsubstr == '\0') // 匹配成功
        {
            return num;
        }
    }
    return -1;
}

char *MyStrtok(char *scr, char sign, int index)
{
    char *tar = (char *)malloc(100); // 开辟堆空间
    int i = 0;
    int flag = 0;
    int startpos = 0;
    int endpos = 0;
    while (scr[i] != '\0')
    {
        if (scr[i] == sign)
        {
            flag++;
            if (flag == index - 1)
            {
                startpos = i + 1;
            }
            if (flag == index)
            {
                endpos = i;
            }
        }
        i++;
    }
    if (endpos == 0) // 用于查找最后一个，此时字符串末尾的'\0'可以当做','
    {
        endpos = i;
    }
    strncpy(tar, scr + startpos, endpos - startpos);
    return tar;
}

char Total_Length_String[15] = {0};
int Get_http_bin_file_body(char *str, char *result, int *binlen)
{
    int Content_length_pos = 0;
    int Content_Type_pos = 0;
    int Body_Start_pos = 0;
    int Connection_pos = 0;
    int Total_Index_pos = 0;
    int Total_Start_pos = 0;
    int Total_End_pos = 0;
    int pos_len = 0;
    int body_length = 0;
    char total_length_pos[50];
    char total_length_buf[15];
    static char firstGetBin = 1;

    if (1 == firstGetBin)
    {
        FirmwareInfo.BinCurrentNo = 0;
        Total_Index_pos = MyStrstr(str, "Range:");
        memcpy(total_length_pos, str + Total_Index_pos, 25);
        sscanf(total_length_pos, "%*[^/]/%[^\r]", total_length_buf);
        memcpy(Total_Length_String, total_length_buf, 15);
        // sscanf(total_length_buf, "%d", &firmwarelength);
        ESP_LOGI(TAG, "total_length_buf=%s", total_length_buf);
        // 如果缓存非空并且，总长大于10而且都是数字
        if (total_length_buf != NULL && sizeof(total_length_buf) >= 10 &&
            strspn(total_length_buf, "0123456789") == strlen(total_length_buf))
        {
            sscanf(total_length_buf, "%d", &firmwarelength);
            ESP_LOGI(TAG, "firmwarelength=%d", firmwarelength);
        }
        // 获取长度失败，重新获取
        else
        {
            ESP_LOGE(TAG, "firmwarelength Get Error , Retry !!!!!");
            return 1;
        }
        send_ota_Info();
        if (1 != OTAflag)
            return 1;
        else
            firstGetBin = 0;
    }

    Content_length_pos = MyStrstr(str, "Content-Length");
    Content_Type_pos = MyStrstr(str, "Content-Type");
    ESP_LOGD(TAG, "Content-Length is %d", Content_length_pos);
    Body_Start_pos = MyStrstr(str, "\r\n\r\n");
    Connection_pos = MyStrstr(str, "Last-Modified");
    pos_len = Connection_pos - sizeof("Content-Length: \n") - Content_length_pos;
    for (int i = 0; i < (pos_len); i++)
    {
        ESP_LOGD(TAG, "recv_buf_temp[%d] = %c \n", Content_length_pos + sizeof("Content-Length: ") + i - 1,
                 str[Content_length_pos + sizeof("Content-Length: ") + i - 1]);
        body_length += (str[Content_length_pos + sizeof("Content-Length: ") + i - 1] - '0') * pow(10, (pos_len - i - 1));
    }
    ESP_LOGI(TAG, "body_length = %d \n", body_length);
    ESP_LOGI(TAG, "Body_Start_pos = %d \n", Body_Start_pos);
    if (body_length == 0 || Content_length_pos == -1)
        return 1;
    // NOTE: 可能是最后一包
    if (body_length < 512 && body_length > 0)
    {
        // 进行判断是否是最后一包
        ESP_LOGI(TAG, "Last Packger !!!!!!!!!!!!");
        // NOTE: 4个字节的\r\n\r\n
        memcpy(result, str + Body_Start_pos + 4, body_length);
        *binlen = body_length;
        return 2;
    }
    else if (body_length == 512)
    {
        // NOTE: 4个字节的\r\n\r\n
        memcpy(result, str + Body_Start_pos + 4, body_length);
        *binlen = body_length;
        ESP_LOGI(TAG, "!!!!!!Get Data !!!!!");
        // for (int i = 0; i < body_length; i++)
        // {
        // putchar(result[i]);
        // printf("%x", result[i]);
        // }
    }
    return 0;
}
static void __ota_for_Accessories(FIRMWARE_INFO FirmInfo)
{
    cJSON *cjson_OTA = NULL;

    const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    int bin_length;
    int offset_start = 0, offset_stop = 511;
    static int fail_cnt = 0;
    char HTTP_Status = 0;

    int OTA_Pack = 0;
    uint32_t OTA_Total = 0;
    float OTA_Progress = 0.0f;
    char str[512] = {0};
    char Progress_str[64] = {0};
    char Pak_str[64] = {0};

    // char http_request[512];
    HttpInfo_t *httpinfo;
    httpinfo = malloc(sizeof(HttpInfo_t));
    httpinfo->URL = FirmInfo.url;
    sscanf(httpinfo->URL + 7, "%[^:]", httpinfo->Server);

    sscanf(httpinfo->URL + 7 + strlen(httpinfo->Server) + 1, "%[^/]", httpinfo->Port);
    ESP_LOGI(TAG, "\r\nhttpinfo->Server is %s\r\nhttpinfo->Port is %s", httpinfo->Server, httpinfo->Port);

    /*发送bin信息，且让主控单片机进入升级模式*/
    send_GoIntoOTA();
    if (1 != OTAflag)
        return; // goto exit;
    while (1)
    {
        cjson_OTA = cJSON_CreateObject();
        sprintf(httpinfo->Request, "GET "
                                   "%s"
                                   " HTTP/1.0\r\n"
                                   "Host: "
                                   "%s"
                                   ":"
                                   "%s"
                                   "\r\n"
                                   "Range: bytes=%d-%d\r\n"
                                   "User-Agent: DCC/WIFI1\r\n"
                                   "\r\n",
                (char *)httpinfo->URL, (char *)httpinfo->Server, (char *)httpinfo->Port, offset_start, offset_stop);

        ESP_LOGI(TAG, "http request is:\r\n"
                      "%s",
                 httpinfo->Request);
        int err = getaddrinfo(httpinfo->Server, httpinfo->Port, &hints, &res);

        if (err != 0 || res == NULL)
        {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }

        /* Code to print the resolved IP.

           Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));

        s = socket(res->ai_family, res->ai_socktype, 0);
        if (s < 0)
        {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if (connect(s, res->ai_addr, res->ai_addrlen) != 0)
        {
            ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

        ESP_LOGI(TAG, "... connected");
        freeaddrinfo(res);

        if (write(s, httpinfo->Request, strlen(httpinfo->Request)) < 0)
        {
            ESP_LOGE(TAG, "... socket send failed");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        struct timeval receiving_timeout;
        receiving_timeout.tv_sec = 5;
        receiving_timeout.tv_usec = 0;
        if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
                       sizeof(receiving_timeout)) < 0)
        {
            ESP_LOGE(TAG, "... failed to set socket receiving timeout");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... set socket receiving timeout success");

        bzero(recv_buf_temp, sizeof(recv_buf_temp));
        bzero(recv_bin_file_temp, sizeof(recv_bin_file_temp));
        /* Read HTTP response */
        do
        {
            r = read(s, recv_buf_temp, sizeof(recv_buf_temp) - 1);
            for (int i = 0; i < r; i++) // 打印收到的数据
            {
                putchar(recv_buf_temp[i]);
            }
        } while (r > 0);

        ESP_LOGI(TAG, "-----------Body is --------");
        HTTP_Status = Get_http_bin_file_body(recv_buf_temp, recv_bin_file_temp, &bin_length);
        // 获取HTTP包失败的情况，不进行增加
        if (HTTP_Status == 1)
        {
            fail_cnt++;
            ESP_LOGI(TAG, "fail_cnt: %d", fail_cnt);
            // goto exit;
        }
        // 成功情况
        else if (HTTP_Status == 0)
        {
            OTA_Pack++;
            offset_start += 512;
            offset_stop += 512;

            // 发送数据
            send_ota_bin(recv_bin_file_temp, bin_length);
            ESP_LOGI(TAG, "OTAflag: %d", OTAflag);

            OTA_Total = atoi(Total_Length_String);
            ESP_LOGI(TAG, "%d", OTA_Total);
            OTA_Progress = (512.0 * OTA_Pack) / (float)OTA_Total;
            ESP_LOGI(TAG, "%f", OTA_Progress);
            sprintf(Progress_str, "%d%%", (int)(OTA_Progress * 100));
            sprintf(Pak_str, "%d", (OTA_Pack * 512));

            if (1 != OTAflag)
                goto exit;
        }
        // NOTE:此为全部完成
        else if (HTTP_Status == 2)
        {
            sprintf(Pak_str, "%d", atoi(Total_Length_String));
            sprintf(Progress_str, "%d%%", (int)(1 * 100));
            recv_bin_last_package_length = bin_length;
            memcpy(recv_bin_last_package, recv_bin_file_temp, bin_length);
            OTAflag = 3;
            send_ota_bin(recv_bin_file_temp, bin_length); // 发送数据
            if (1 != OTAflag)
                goto exit;

            close(s);
            bzero(recv_buf_temp, sizeof(recv_buf_temp));
            bzero(recv_bin_file_temp, sizeof(recv_bin_file_temp));
            ESP_LOGI(TAG, "OTA Finish");
            vTaskDelay(20 / portTICK_PERIOD_MS);
            // uart_driver_delete(UART_NUM_2);
            // vTaskDelete(NULL);
            // break;
        }
        ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);

        // NOTE:一旦关闭数据消失
        close(s);

        bzero(recv_buf_temp, sizeof(recv_buf_temp));
        bzero(recv_bin_file_temp, sizeof(recv_bin_file_temp));
        vTaskDelay(20 / portTICK_PERIOD_MS);
        ESP_LOGI(TAG, "Starting again!");

        // NOTE: STM32上传升级的进度
        ESP_LOGI(TAG, "Update OTA Progress!!");
        /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Type", "MCU");
        /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "TotalLength", Total_Length_String);
        /* 添加一条整数类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "CurrentLength", Pak_str);
        /* 添加一条浮点类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Progress", Progress_str);
        /* 打印JSON对象(整条链表)的所有数据 */
        memcpy(str, cJSON_Print(cjson_OTA), 512);
        ESP_LOGI(TAG, "%s", str);
        esp_mqtt_client_publish(user_client, (const char *)&ota_progress_topic, (const char *)str, strlen(str), 0, 0);
        // 清除
        cJSON_Delete(cjson_OTA);
        bzero(str, sizeof(str));
    }
exit:
    close(s);
    bzero(recv_buf_temp, sizeof(recv_buf_temp));
    bzero(recv_bin_file_temp, sizeof(recv_bin_file_temp));
    free(httpinfo);
    ESP_LOGI(TAG, "OTAflag %d HTTP_Status %d Progress_str %s", OTAflag, HTTP_Status, Progress_str);
    if (OTAflag == 3)
    {
        /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Type", "MCU");
        /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Total Length", Total_Length_String);
        /* 添加一条整数类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Current length", Pak_str);
        /* 添加一条浮点类型的JSON数据(添加一个链表节点) */
        cJSON_AddStringToObject(cjson_OTA, "Progress", Progress_str);
        /* 打印JSON对象(整条链表)的所有数据 */
        memcpy(str, cJSON_Print(cjson_OTA), 512);
        ESP_LOGI(TAG, "%s", str);
        esp_mqtt_client_publish(user_client, (const char *)&ota_progress_topic, (const char *)str, strlen(str), 0, 0);
        // 清除
        cJSON_Delete(cjson_OTA);
        bzero(str, sizeof(str));
    }
}

void app_http_task(void *para)
{
    char rxmsg[500] = {[0 ... 499] = 0};
    char i, versionOKflag = 0;
    CHECK_ERROR_CODE(TAG, esp_task_wdt_add(NULL), ESP_OK);
    CHECK_ERROR_CODE(TAG, esp_task_wdt_status(NULL), ESP_OK);
    while (1)
    {
        CHECK_ERROR_CODE(TAG, esp_task_wdt_reset(), ESP_OK);
        if (xQueueReceive(start_OTA_queue, &rxmsg, pdMS_TO_TICKS(1000)))
        {
            ESP_LOGI(TAG, "OTA Begin");
            CHECK_ERROR_CODE(TAG, esp_task_wdt_delete(NULL), ESP_OK);
            CHECK_ERROR_CODE(TAG, esp_task_wdt_status(NULL), ESP_ERR_NOT_FOUND);
            cJSON *pJsonRoot = cJSON_Parse(rxmsg);
            if (!pJsonRoot)
            {
                printf("Error before: [%s]\n", cJSON_GetErrorPtr());
            }
            else
            {
                char *s = cJSON_Print(pJsonRoot);
                ESP_LOGI(TAG, "pJsonRoot: %s\r\n", s);
                cJSON_free((void *)s);
                // 解析URL字段
                cJSON *pURL = cJSON_GetObjectItem(pJsonRoot, "url");
                if (pURL)
                {
                    ESP_LOGI(TAG, "URL:%s \n", pURL->valuestring);
                }
                // 解析version字段       格式XXX.XXX.XXX每段两个字节
                cJSON *pSerialVersion = cJSON_GetObjectItem(pJsonRoot, "version");
                if (pSerialVersion)
                {
                    char *p = strtok(pSerialVersion->valuestring, ".");
                    for (i = 3; i > 0; i--)
                    {
                        FirmwareInfo.version[i - 1] = atoi(p);
                        ESP_LOGI(TAG, "FirmwareInfo.version[%d] = %d \n", i - 1, FirmwareInfo.version[i - 1]);
                        p = strtok(NULL, ".");
                        if (!p)
                            break;
                    }
                }
                //----------------解析mods字段----------------
                cJSON *pMods = cJSON_GetObjectItem(pJsonRoot, "mods");
                if (pMods)
                {
                    // 解析主控模块字段
                    cJSON *pMattress = cJSON_GetObjectItem(pMods, "mattress");
                    if (pMattress)
                    {
                        // 解析 主控-version模块字段
                        cJSON *pMattress_version = cJSON_GetObjectItem(pMattress, "version");
                        if (pMattress_version)
                        {
                            char *p1 = strtok(pMattress_version->valuestring, ".");
                            for (i = 4; i > 0; i--)
                            {
                                FirmwareInfo.mattress_version[i - 1] = atoi(p1);
                                ESP_LOGI(TAG, "mattress Version[%d] = %d \n", i - 1, FirmwareInfo.mattress_version[i - 1]);
                                p1 = strtok(NULL, ".");
                                if (!p1)
                                    break;
                            }
                            if ((FirmwareInfo.mattress_version[0] != app_info.mattress_version[0]) || (FirmwareInfo.mattress_version[1] != app_info.mattress_version[1]) || (FirmwareInfo.mattress_version[2] != app_info.mattress_version[2]) || (FirmwareInfo.mattress_version[3] != app_info.mattress_version[3]))
                            {
                                versionOKflag = 1;
                            }
                            else
                            {
                                ESP_LOGI(TAG, "FirmwareInfo: same Version ");
                            }
                        }
                        versionOKflag = 1; // pan升级测试,不监测版本是否相同///////////////////////////////
                        if (1 == versionOKflag)
                        {
                            // 解析 主控-path模块字段
                            cJSON *pMattress_path = cJSON_GetObjectItem(pMattress, "path");
                            if (pMattress_path)
                            {
                                if (cJSON_IsString(pMattress_path))
                                {
                                    char *webURL = malloc(strlen(pURL->valuestring) + strlen(pMattress_path->valuestring) + 10);
                                    sprintf(webURL, "%s/%s", pURL->valuestring, pMattress_path->valuestring);
                                    FirmwareInfo.url = webURL;
                                    ESP_LOGI(TAG, "FirmwareInfo Url:%s", FirmwareInfo.url);
                                    SendToServerOTAbegin(); // MQTT通知开始升级
                                    //------升级GD32模块------------------
                                    __ota_for_Accessories(FirmwareInfo);
                                    if (3 == OTAflag)
                                    {
                                        // //读取配网信息
                                        // size_t NVSlen = 0;
                                        // // 读取保存数据
                                        // user_nvs_read_blob(NVS_APP_INFO, NULL, &NVSlen);
                                        // user_nvs_read_blob(NVS_APP_INFO, &app_info,&NVSlen);
                                        app_info.mattress_version[0] = FirmwareInfo.mattress_version[0];
                                        app_info.mattress_version[1] = FirmwareInfo.mattress_version[1];
                                        app_info.mattress_version[2] = FirmwareInfo.mattress_version[2];
                                        app_info.mattress_version[3] = FirmwareInfo.mattress_version[3];
                                        app_info.version[0] = FirmwareInfo.version[2];
                                        app_info.version[1] = FirmwareInfo.version[1];
                                        app_info.version[2] = FirmwareInfo.version[0];
                                        // ESP_ERROR_CHECK(user_nvs_save_blob(NVS_APP_INFO, &app_info, sizeof(app_info)));
                                        ESP_LOGI(TAG, "\n\nota mattress success !\n\n");
                                    }
                                    else
                                    {
                                        ESP_LOGI(TAG, "\n\nota mattress fail !\n\n");
                                    }
                                    free(webURL);
                                }
                            }
                        }
                    }
                    // 解析wifi模块字段
                    cJSON *pWifi = cJSON_GetObjectItem(pMods, "wifi");
                    if (pWifi)
                    {
                        // 解析wifi-path模块字段
                        cJSON *pWifi_path = cJSON_GetObjectItem(pWifi, "path");
                        if (pWifi_path)
                        {
                            if (cJSON_IsString(pWifi_path))
                            {
                                char *webURL = malloc(strlen(pURL->valuestring) + strlen(pWifi_path->valuestring) + 10);
                                sprintf(webURL, "%s/%s", pURL->valuestring, pWifi_path->valuestring);
                                ESP_LOGI(TAG, "Wifi webURL:%s", webURL);
                                //------升级本身WiFi模块------------------
                                __ota_for_self(webURL);
                                free(webURL);
                            }
                        }
                    }
                }
            }
            CHECK_ERROR_CODE(TAG, esp_task_wdt_add(NULL), ESP_OK);
            CHECK_ERROR_CODE(TAG, esp_task_wdt_status(NULL), ESP_OK);
        }
    }
}
